﻿module tilingTools

open System
open System.Windows
open System.Windows.Markup
open System.Windows.Controls
open consoleApp
open System.Threading

//
//type consoleClass() = 
//    // declare this real quickly?
//    let window = new consoleWindow()
//    do
//        window.Show()
//        window.addText("RectLibrary console: \n---------------------------------------");
//    member this.add(s : string) =
//        window.addText(s)
//    member this.startThread() =
//        window.Show()
//        System.Windows.Threading.Dispatcher.Run()

//let startupConsole = 
//    // declare this real quickly?
let conWindow = new consoleWindow()
conWindow.Show()
let conTextAdd (s : string) =
    conWindow.addText(s)

conWindow.addText("RectLibrary console: \n---------------------------------------");

//let consoleObject = new consoleClass()
//let (consoleThread : Thread) = new Thread(new ThreadStart(consoleObject.startThread))
//consoleThread.SetApartmentState(ApartmentState.STA)
//consoleThread.IsBackground <- true
//consoleThread.Start()

// sort the array so that it is in northwest, northeast, southeast, southwest order
let sortVertices (V : (int * int) array array) =
    let n = V.GetLength 0
    let mutable newArray = [||]
    for i = 0 to n-1 do
        let sortedV = Array.sort V.[i]
        let processedV = [|Array.find (fun elem -> ((snd elem = snd sortedV.[-1 + (sortedV.GetLength 0)]) && (fst elem = fst sortedV.[0]))) sortedV;sortedV.[-1 + (sortedV.GetLength 0)];Array.find (fun elem -> ((fst elem = fst sortedV.[-1 + (sortedV.GetLength 0)]) && (snd elem = snd sortedV.[0]))) sortedV;sortedV.[0]|]
        // newArray <- Array.append newArray [|[|normSortedV.[1];normSortedV.[3];normSortedV.[2];normSortedV.[0]|]|]
        newArray <- Array.append newArray [|processedV|]
    done

    let mutable finishedArray = [||]
    // now that they're all sorted, let's truncate-ish them so that they turn into tiles, rather than vertices
    for i = 0 to n-1 do
        // this is one set of vertices
        let mutable finishedArrayPart = newArray.[i]
        let maxX = finishedArrayPart |> Array.map (fun elem -> fst elem) |> Array.max
        let maxY = finishedArrayPart |> Array.map (fun elem -> snd elem) |> Array.max
        let minX = finishedArrayPart |> Array.map (fun elem -> fst elem) |> Array.min
        let minY = finishedArrayPart |> Array.map (fun elem -> snd elem) |> Array.min
        for p = 0 to 3 do
            if (fst finishedArrayPart.[p] = maxX) then
                if (snd finishedArrayPart.[p] = maxY) then
                    finishedArrayPart.[p] <- (((fst finishedArrayPart.[p]) - 1), ((snd finishedArrayPart.[p]) - 1))
                else
                    finishedArrayPart.[p] <- (((fst finishedArrayPart.[p]) - 1), (snd finishedArrayPart.[p]))
            elif (snd finishedArrayPart.[p] = maxY) then
                finishedArrayPart.[p] <- ((fst finishedArrayPart.[p]), ((snd finishedArrayPart.[p]) - 1))
            // if -1 + whatever minX is : is not 0, then we will accept it
//            if ((fst finishedArrayPart.[p] = minX) && ((-1+minX) >= 0)) then
//                if ((snd finishedArrayPart.[p] = minY) && ((-1+minY) >= 0)) then
//                    finishedArrayPart.[p] <- (((fst finishedArrayPart.[p]) - 1), ((snd finishedArrayPart.[p]) - 1))
//                else
//                    finishedArrayPart.[p] <- (((fst finishedArrayPart.[p]) - 1), (snd finishedArrayPart.[p]))
//            elif ((snd finishedArrayPart.[p] = minY) && ((-1+minY) >= 0)) then
//                finishedArrayPart.[p] <- ((fst finishedArrayPart.[p]), ((snd finishedArrayPart.[p]) - 1))
        done
        //let indexX = Array.findIndex (fun elem -> (fst elem = maxX)) finishedArrayPart
        //let indexY = Array.findIndex (fun elem -> (snd elem = maxY)) finishedArrayPart
        //finishedArrayPart.[indexX] <- (((fst finishedArrayPart.[indexX]) - 1), (snd finishedArrayPart.[indexX]))
        //finishedArrayPart.[indexY] <- ((fst finishedArrayPart.[indexY]), ((snd finishedArrayPart.[indexY]) - 1))
        finishedArray <- Array.append finishedArray [|finishedArrayPart|]
    done
    
    conTextAdd ("newArray: "+ sprintf "%A" newArray)
    //printfn "newArray: %A" newArray
    conTextAdd ("finishedArray: "+ sprintf "%A" finishedArray)
    //printfn "finishedArray: %A" finishedArray
    finishedArray
    //newArray

let createTiles (V : (int * int) array array) = 
    // we receive a array of vectors containing corner coordinates going horizontally
    // this allows us to determine each shape and which shapes have similar sides to allow for multiple glues
    // our output is planned to be an array of string arrays as follows:
    // [blockID tileCoordinateX tileCoordinateY tileNorthGlueType tileEastGlueType tileSouthGlueType tileWestGlueType]
    // where each glueType #B signifies: 0 for no glue, 1 for strength 1 glue, 2 for strength 2 glue; B for neighboring border tile, F for filler, or X for no bordering
    // this output will be passed to an interpreter that will determine which glues (and its reverse) will be applied to which tile

    // example single array: [|Block 1; 0; 0; 0X; 2B; 1F; 0X;|]

    // number of rectangles
    let n = V.GetLength 0
    
    let mutable workingOutputAppendix = [||]

    // Determining glue type of borders by trying to find the index and then using that index to test where pointArray is an array with points other than the current point's shape
    let detGlueType (direction : string) (point : int * int) (currentArray : (int * int) []) (pointArray : (int * int) [][]) = 
        let mutable glueType = "0X"
        let j = pointArray.GetLength 0
        // *** WORK ON IF POINTARRAY DOESN'T EXIST
        if (pointArray.GetLength 0) <> 0 then
            for i = 0 to -1 + j do
                if direction = "North" then
                    // if anything with y+1 exists
                    if (Array.tryFind (fun elem -> ((snd elem = (1 + snd point)) && (fst elem = fst point))) pointArray.[i]) <> None then
                        glueType <- "2N"
                    // if this is a border tile, at least one side isn't bordered
                    elif (((Array.tryFind (fun elem -> (fst elem = 1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) = None) || (Array.tryFind (fun elem -> (fst elem = -1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) = None) && ((Array.tryFind (fun elem -> (snd elem = 1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) <> None) then
                        glueType <- "2B"
                    elif (Array.tryFind (fun elem -> ((snd elem = (1 + snd point)) && (fst elem = fst point) && (elem <> point))) currentArray) <> None then
                        glueType <- "1F"
                elif direction = "East" then
                    // if anything with x+1 exists
                    if (Array.tryFind (fun elem -> ((fst elem = (1 + fst point)) && (snd elem = snd point))) pointArray.[i]) <> None then
                        glueType <- "2N"
                    // if this is a border tile, at least one side isn't bordered
                    elif (((Array.tryFind (fun elem -> (snd elem = 1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) = None) || (Array.tryFind (fun elem -> (snd elem = -1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) = None) && ((Array.tryFind (fun elem -> (fst elem = 1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) <> None) then
                        glueType <- "2B"
                    elif (Array.tryFind (fun elem -> ((fst elem = (1 + fst point)) && (snd elem = snd point) && (elem <> point))) currentArray) <> None then
                        glueType <- "1F"
                elif direction = "South" then
                    // if anything with y-1 exists
                    if (Array.tryFind (fun elem -> ((snd elem = (-1 + snd point)) && (fst elem = fst point))) pointArray.[i]) <> None then
                        glueType <- "2N"
                    // if this is a border tile, at least one side isn't bordered
                    elif (((Array.tryFind (fun elem -> (fst elem = 1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) = None) || (Array.tryFind (fun elem -> (fst elem = -1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) = None) && ((Array.tryFind (fun elem -> (snd elem = -1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) <> None) then
                        glueType <- "2B"
                    elif (Array.tryFind (fun elem -> ((snd elem = (-1 + snd point)) && (fst elem = fst point) && (elem <> point))) currentArray) <> None then
                        glueType <- "1F"
                elif direction = "West" then
                    // if anything with x-1 exists
                    if (Array.tryFind (fun elem -> ((fst elem = (-1 + fst point)) && (snd elem = snd point))) pointArray.[i]) <> None then
                        glueType <- "2N"
                    // if this is a border tile, at least one side isn't bordered
                    elif (((Array.tryFind (fun elem -> (snd elem = 1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) = None) || ((Array.tryFind (fun elem -> (snd elem = -1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) = None)) && ((Array.tryFind (fun elem -> (fst elem = -1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) <> None) then
                        glueType <- "2B"
                    elif (Array.tryFind (fun elem -> ((fst elem = (-1 + fst point)) && (snd elem = snd point) && (elem <> point))) currentArray) <> None then
                        glueType <- "1F"
            done
        else
            if direction = "North" then
                // if this is a border tile, at least one side isn't bordered
                if (((Array.tryFind (fun elem -> (fst elem = 1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) = None) || ((Array.tryFind (fun elem -> (fst elem = -1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) = None)) && ((Array.tryFind (fun elem -> (snd elem = 1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) <> None) then
                    glueType <- "2B"
                elif (Array.tryFind (fun elem -> ((snd elem = (1 + snd point)) && (fst elem = fst point) && (elem <> point))) currentArray) <> None then
                    glueType <- "1F"
            elif direction = "East" then
                // if this is a border tile, at least one side isn't bordered
                if (((Array.tryFind (fun elem -> (snd elem = 1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) = None) || ((Array.tryFind (fun elem -> (snd elem = -1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) = None)) && ((Array.tryFind (fun elem -> (fst elem = 1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) <> None) then
                    glueType <- "2B"
                elif (Array.tryFind (fun elem -> ((fst elem = (1 + fst point)) && (snd elem = snd point) && (elem <> point))) currentArray) <> None then
                    glueType <- "1F"
            elif direction = "South" then
                // if this is a border tile, at least one side isn't bordered
                if (((Array.tryFind (fun elem -> (fst elem = 1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) = None) || ((Array.tryFind (fun elem -> (fst elem = -1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) = None)) && ((Array.tryFind (fun elem -> (snd elem = -1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) <> None) then
                    glueType <- "2B"
                elif (Array.tryFind (fun elem -> ((snd elem = (-1 + snd point)) && (fst elem = fst point) && (elem <> point))) currentArray) <> None then
                    glueType <- "1F"
            elif direction = "West" then
                // if this is a border tile, at least one side isn't bordered
                if (((Array.tryFind (fun elem -> (snd elem = 1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) = None) || ((Array.tryFind (fun elem -> (snd elem = -1 + snd point) && (elem <> point) && (fst point = fst elem)) currentArray) = None)) && ((Array.tryFind (fun elem -> (fst elem = -1 + fst point) && (elem <> point) && (snd point = snd elem)) currentArray) <> None) then
                    glueType <- "2B"
                elif (Array.tryFind (fun elem -> ((fst elem = (-1 + fst point)) && (snd elem = snd point) && (elem <> point))) currentArray) <> None then
                    glueType <- "1F"
        glueType

    // create list of coordinates for x side
    let createXside x0 x1 =
        let x = x1-x0
        // if tiling direction is going west
        if x < 0 then
            let outputX = [ for i in 0 .. (abs x) -> x0 - i ]
            outputX
        // if tiling direction is going east
        else
            // List.rev
            let outputX = [ for i in 0 .. (abs x) -> x1 - i ]
            outputX
    // create list of coordinates for y side
    let createYside y0 y1 =
        let y = y1-y0
        // if tiling direction is going south
        if y < 0 then
            let outputY = [ for i in 0 .. (abs y) -> y0 - i ]
            outputY
        // if tiling direction is going north
        else
            let outputY = [ for i in 0 .. (abs y) -> y1 - i ]
            outputY

    // produce an array of usable borders from the vertices in each shape (input must be V.[shapeIndex])
    let drawBorders (V : (int * int) []) = 
        // output schema is an array of arrays of coordinates that make up borders of the input vertexArray V
        let mutable borders = [||]
        let redoVertices = Array.append V [|V.[0]|]
        // we will create an array of arrays so that the appending will work correctly
        // each j is a coordinate of a vertex (corner) of the rectangle (we assume 4)
        // thus for each j we would do one side (ORDER MUST BE: northwest, northeast, southeast, southwest) (north, east, south, west)
        let numborders = redoVertices.Length
        conWindow.addText ("Determining " + string (numborders-1) + " borders..." )
        let mutable sideTempArray = [||]
        for j = 1 to 4 do
            conTextAdd ("Determining border "+(string j)+"...")
            // create the sides (border tiles)
            // creating coordinates
            let x0 = fst redoVertices.[j-1]
            let y0 = snd redoVertices.[j-1]
            let x1 = fst redoVertices.[j]
            let y1 = snd redoVertices.[j]

            // tiles are horizontal
            if x0 <> x1 && y0 = y1 then
                let side = createXside x0 x1
                let p = side.Length
                // append new side
                // sideTempArray <- Array.append sideTempArray (Array.init p (fun index -> (side.[index], y0)))
                sideTempArray <- Array.init p (fun index -> (side.[index], y0))
            // tiles are vertical
            elif x0 = x1 && y0 <> y1 then
                let side = createYside y0 y1
                let o = side.Length
                // append new side
                sideTempArray <- Array.init o (fun index -> (x0, side.[index]))
            borders <- Array.append borders [|sideTempArray|]
        done
        printfn "borders: %A" borders
        borders

    // produce a usable grid from the bordersFullArray (array of borders)
    let produceGrid (borders : (int * int) [][]) =
        let xLength = borders.[0].GetLength 0
        let mutable gridList = [||]
        for i = 0 to xLength-1 do
            // creating coordinates
            let x0 = fst borders.[2].[i]
            let y0 = snd borders.[2].[i]
            let x1 = fst borders.[0].[i]
            let y1 = snd borders.[0].[i]
            // tiles are vertically drawn
            if x0 = x1 && y0 <> y1 then
                let side = createYside y0 y1
                let o = side.Length
                // append new side
                gridList <- Array.append gridList (Array.init o (fun index -> (x0, side.[index])))
            // report an error
            else
                conTextAdd "error in assumption of order."
        done
        gridList

    (* Begin wrapper function *)
    let mutable tiles = [||]
    let doTiling =
        for i = 0 to n-1 do
            let currentArray = produceGrid (drawBorders V.[i])
            let notCurrentVerticesArray = V |> Array.filter (fun elem -> elem <> V.[i])
            let pointsArray = Array.map (fun elem -> produceGrid (drawBorders elem)) notCurrentVerticesArray
            workingOutputAppendix <- Array.map (fun elem -> [|"B" + (string i); string (fst elem); string (snd elem); detGlueType "North" elem currentArray pointsArray; detGlueType "East" elem currentArray pointsArray; detGlueType "South" elem currentArray pointsArray; detGlueType "West" elem currentArray pointsArray;|]) currentArray
            tiles <- Array.append tiles workingOutputAppendix
        done
    
    let sortGlues =
        let n = tiles.GetLength 0
        // we should first look for if the glue shares a border with another tile, depending on the North, East, South, or West sides.
        // we start alphanumerically (in ascii code of course), when the integer after reaches 9 (when i = 10), we add one to the ascii code
        // e.g. (string (char 97)) + (string i) + (string bool complimentary?)
        // search for complimentary tile
        let findCompTileIndex (side : string) (currTileX : string) (currTileY : string) (currTileGlue : string) (tiles : string [][]) =
            let mutable tileIndex = 0
            if currTileGlue <> "0X" then
                let mutable gluePos = 0
                if side = "North" then
                    let compNorthAttach = tiles |> Array.findIndex (fun elem -> (elem.[5] = currTileGlue) && (elem.[1] = currTileX) && (elem.[2] = string ((int currTileY) + 1)))
                    tileIndex <- compNorthAttach
                elif side = "East" then
                    let compEastAttach = tiles |> Array.findIndex (fun elem -> (elem.[6] = currTileGlue) && (elem.[1] = string ((int currTileX) + 1)) && (elem.[2] = currTileY))
                    tileIndex <- compEastAttach
                elif side = "South" then
                    let compSouthAttach = tiles |> Array.findIndex (fun elem -> (elem.[3] = currTileGlue) && (elem.[1] = currTileX) && (elem.[2] = string ((int currTileY) - 1)))
                    tileIndex <- compSouthAttach
                elif side = "West" then
                    let compWestAttach = tiles |> Array.findIndex (fun elem -> (elem.[4] = currTileGlue) && (elem.[1] = string ((int currTileX) - 1)) && (elem.[2] = currTileY))
                    tileIndex <- compWestAttach
                else
                    failwith "No glue side specified."
            tileIndex
        let finalTiles = Array.copy tiles
        let tileGlues =
            let finalOutput = Array.init (Array.length finalTiles) (fun elem -> [|finalTiles.[elem].[0];finalTiles.[elem].[1];finalTiles.[elem].[2];"";"";"";""|])
            // we still have our old buddy finalTiles. Now we see what finalTiles has and write it into the finalOutput
            // we accomplish this by going in order, looking for complements each time and assigning some kind of index value to add next to the ascii. we will run two indices?
            let mutable intACount = 0
            let mutable intBCount = 0
            let intFCount = 0 // not sure if this needs to be mutable or not, since we theoretically only need a single weak filler
            // we won't bother with ascii. ALL 2N = 'A'-class glues, 2B = 'B'-class glues, 1F = 'F'-class glues
            // thus each glue looks like "Axxu" where xx = int and u = 'c' or non-existant
            for n = 0 to -1 + Array.length finalOutput do
                // assign the North glues first
                if finalTiles.[n].[3] <> "0X" && finalOutput.[n].[3] = "" then
                    printfn "searching for a tile north of %d, %d with similar glue type of %s" (int finalTiles.[n].[1]) (int finalTiles.[n].[2]) finalTiles.[n].[3]
                    let compNorthIndex = findCompTileIndex "North" (finalOutput.[n].[1]) (finalOutput.[n].[2]) finalTiles.[n].[3] finalTiles
                    if finalTiles.[n].[3] = "2N" then
                        finalOutput.[n].[3] <- "A" + (string intACount)
                        finalOutput.[compNorthIndex].[5] <- "A" + (string intACount) + "c"
                        intACount <- intACount + 1
                    elif finalTiles.[n].[3] = "2B" then
                        finalOutput.[n].[3] <- "B" + (string intBCount)
                        finalOutput.[compNorthIndex].[5] <- "B" + (string intBCount) + "c"
                        intBCount <- intBCount + 1
                    elif finalTiles.[n].[3] = "1F" then
                        finalOutput.[n].[3] <- "F" + (string intFCount)
                        finalOutput.[compNorthIndex].[5] <- "F" + (string intFCount) + "c"
                elif finalTiles.[n].[3] = "0X" && finalOutput.[n].[3] = "" then
                    finalOutput.[n].[3] <- "N0X"

                // assign the East glues
                if finalTiles.[n].[4] <> "0X" && finalOutput.[n].[4] = "" then
                    printfn "searching for a tile east of %d, %d with similar glue type of %s" (int finalTiles.[n].[1]) (int finalTiles.[n].[2]) finalTiles.[n].[4]
                    let compNorthIndex = findCompTileIndex "East" (finalOutput.[n].[1]) (finalOutput.[n].[2]) finalTiles.[n].[4] finalTiles
                    if finalTiles.[n].[4] = "2N" then
                        finalOutput.[n].[4] <- "A" + (string intACount)
                        finalOutput.[compNorthIndex].[6] <- "A" + (string intACount) + "c"
                        intACount <- intACount + 1
                    elif finalTiles.[n].[4] = "2B" then
                        finalOutput.[n].[4] <- "B" + (string intBCount)
                        finalOutput.[compNorthIndex].[6] <- "B" + (string intBCount) + "c"
                        intBCount <- intBCount + 1
                    elif finalTiles.[n].[4] = "1F" then
                        finalOutput.[n].[4] <- "F" + (string intFCount)
                        finalOutput.[compNorthIndex].[6] <- "F" + (string intFCount) + "c"
                elif finalTiles.[n].[4] = "0X" && finalOutput.[n].[4] = "" then
                    finalOutput.[n].[4] <- "N0X"

                // assign the South glues
                if finalTiles.[n].[5] <> "0X" && finalOutput.[n].[5] = "" then
                    printfn "searching for a tile south of %d, %d with similar glue type of %s" (int finalTiles.[n].[1]) (int finalTiles.[n].[2]) finalTiles.[n].[5]
                    let compNorthIndex = findCompTileIndex "South" (finalOutput.[n].[1]) (finalOutput.[n].[2]) finalTiles.[n].[5] finalTiles
                    if finalTiles.[n].[5] = "2N" then
                        finalOutput.[n].[5] <- "A" + (string intACount)
                        finalOutput.[compNorthIndex].[3] <- "A" + (string intACount) + "c"
                        intACount <- intACount + 1
                    elif finalTiles.[n].[5] = "2B" then
                        finalOutput.[n].[5] <- "B" + (string intBCount)
                        finalOutput.[compNorthIndex].[3] <- "B" + (string intBCount) + "c"
                        intBCount <- intBCount + 1
                    elif finalTiles.[n].[5] = "1F" then
                        finalOutput.[n].[5] <- "F" + (string intFCount)
                        finalOutput.[compNorthIndex].[3] <- "F" + (string intFCount) + "c"
                elif finalTiles.[n].[5] = "0X" && finalOutput.[n].[5] = "" then
                    finalOutput.[n].[5] <- "N0X"

                // assign the West glues
                if finalTiles.[n].[6] <> "0X" && finalOutput.[n].[6] = "" then
                    printfn "searching for a tile west of %d, %d with similar glue type of %s" (int finalTiles.[n].[1]) (int finalTiles.[n].[2]) finalTiles.[n].[6]
                    let compNorthIndex = findCompTileIndex "West" (finalOutput.[n].[1]) (finalOutput.[n].[2]) finalTiles.[n].[6] finalTiles
                    if finalTiles.[n].[6] = "2N" then
                        finalOutput.[n].[6] <- "A" + (string intACount)
                        finalOutput.[compNorthIndex].[4] <- "A" + (string intACount) + "c"
                        intACount <- intACount + 1
                    elif finalTiles.[n].[6] = "2B" then
                        finalOutput.[n].[6] <- "B" + (string intBCount)
                        finalOutput.[compNorthIndex].[4] <- "B" + (string intBCount) + "c"
                        intBCount <- intBCount + 1
                    elif finalTiles.[n].[6] = "1F" then
                        finalOutput.[n].[6] <- "F" + (string intFCount)
                        finalOutput.[compNorthIndex].[4] <- "F" + (string intFCount) + "c"
                elif finalTiles.[n].[6] = "0X" && finalOutput.[n].[6] = "" then
                    finalOutput.[n].[6] <- "N0X"
            done
            let appendSort = Array.append finalOutput [|[|"Statistics:"; "A = "; string (intACount); "B = "; string (intBCount); "F = "; string (intFCount+1);|]|]
            //finalOutput
            appendSort
        tileGlues
    sortGlues

// *** INPUT MUST BE IN: northwest, northeast, southeast, southwest order.
let test = [|
            [|(0,4);(5,4);(5,0);(0,0)|]
            [|(0,9);(5,9);(5,5);(0,5)|]
            [|(6,6);(9,6);(9,0);(6,0)|]
           |]